Ελληνικά

Απελευθερώστε τη δύναμη της επαναχρησιμοποιήσιμης λογικής στις React εφαρμογές σας με custom hooks. Μάθετε πώς να δημιουργείτε και να αξιοποιείτε custom hooks για πιο καθαρό και συντηρήσιμο κώδικα.

Custom Hooks: Επαναχρησιμοποιήσιμα Πρότυπα Λογικής στη React

Τα React Hooks έφεραν επανάσταση στον τρόπο με τον οποίο γράφουμε React components, εισάγοντας state και χαρακτηριστικά του κύκλου ζωής (lifecycle features) στα functional components. Μεταξύ των πολλών πλεονεκτημάτων που προσφέρουν, τα custom hooks ξεχωρίζουν ως ένας ισχυρός μηχανισμός για την εξαγωγή και επαναχρησιμοποίηση λογικής σε πολλαπλά components. Αυτό το άρθρο θα εμβαθύνει στον κόσμο των custom hooks, εξερευνώντας τα οφέλη, τη δημιουργία και τη χρήση τους με πρακτικά παραδείγματα.

Τι είναι τα Custom Hooks;

Στην ουσία, ένα custom hook είναι μια συνάρτηση JavaScript που ξεκινά με τη λέξη "use" και μπορεί να καλεί άλλα hooks. Σας επιτρέπουν να εξάγετε τη λογική ενός component σε επαναχρησιμοποιήσιμες συναρτήσεις. Αυτός είναι ένας ισχυρός τρόπος για να μοιραστείτε λογική με state (stateful logic), παρενέργειες (side effects) ή άλλες πολύπλοκες συμπεριφορές μεταξύ components, χωρίς να καταφεύγετε σε render props, higher-order components ή άλλα σύνθετα πρότυπα.

Βασικά Χαρακτηριστικά των Custom Hooks:

Οφέλη από τη Χρήση των Custom Hooks

Τα custom hooks προσφέρουν αρκετά σημαντικά πλεονεκτήματα στην ανάπτυξη με React:

Δημιουργώντας το Πρώτο σας Custom Hook

Ας δείξουμε τη δημιουργία ενός custom hook με ένα πρακτικό παράδειγμα: ένα hook που παρακολουθεί το μέγεθος του παραθύρου.

Παράδειγμα: useWindowSize

Αυτό το hook θα επιστρέφει το τρέχον πλάτος και ύψος του παραθύρου του browser. Θα ενημερώνει επίσης αυτές τις τιμές όταν το παράθυρο αλλάζει μέγεθος.

import { useState, useEffect } from 'react';

function useWindowSize() {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    function handleResize() {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }

    window.addEventListener('resize', handleResize);

    // Αφαίρεση του event listener κατά την εκκαθάριση
    return () => window.removeEventListener('resize', handleResize);
  }, []); // Ο κενός πίνακας διασφαλίζει ότι το effect εκτελείται μόνο κατά το mount

  return windowSize;
}

export default useWindowSize;

Επεξήγηση:

  1. Εισαγωγή Απαραίτητων Hooks: Εισάγουμε τα useState και useEffect από τη React.
  2. Ορισμός του Hook: Δημιουργούμε μια συνάρτηση με το όνομα useWindowSize, τηρώντας τη σύμβαση ονοματοδοσίας.
  3. Αρχικοποίηση του State: Χρησιμοποιούμε το useState για να αρχικοποιήσουμε το state windowSize με το αρχικό πλάτος και ύψος του παραθύρου.
  4. Ρύθμιση Event Listener: Χρησιμοποιούμε το useEffect για να προσθέσουμε έναν event listener 'resize' στο παράθυρο. Όταν το μέγεθος του παραθύρου αλλάζει, η συνάρτηση handleResize ενημερώνει το state windowSize.
  5. Εκκαθάριση: Επιστρέφουμε μια συνάρτηση εκκαθάρισης από το useEffect για να αφαιρέσουμε τον event listener όταν το component γίνεται unmount. Αυτό αποτρέπει διαρροές μνήμης (memory leaks).
  6. Επιστρεφόμενες Τιμές: Το hook επιστρέφει το αντικείμενο windowSize, που περιέχει το τρέχον πλάτος και ύψος του παραθύρου.

Χρήση του Custom Hook σε ένα Component

Τώρα που δημιουργήσαμε το custom hook μας, ας δούμε πώς να το χρησιμοποιήσουμε σε ένα React component.

import React from 'react';
import useWindowSize from './useWindowSize';

function MyComponent() {
  const { width, height } = useWindowSize();

  return (
    

Πλάτος παραθύρου: {width}px

Ύψος παραθύρου: {height}px

); } export default MyComponent;

Επεξήγηση:

  1. Εισαγωγή του Hook: Εισάγουμε το custom hook useWindowSize.
  2. Κλήση του Hook: Καλούμε το hook useWindowSize μέσα στο component.
  3. Πρόσβαση στις Τιμές: Κάνουμε destructuring στο επιστρεφόμενο αντικείμενο για να πάρουμε τις τιμές width και height.
  4. Απόδοση Τιμών: Αποδίδουμε τις τιμές του πλάτους και του ύψους στο UI του component.

Οποιοδήποτε component χρησιμοποιεί το useWindowSize θα ενημερώνεται αυτόματα όταν αλλάζει το μέγεθος του παραθύρου.

Πιο Σύνθετα Παραδείγματα

Ας εξερευνήσουμε μερικές πιο προχωρημένες περιπτώσεις χρήσης για custom hooks.

Παράδειγμα: useLocalStorage

Αυτό το hook σας επιτρέπει να αποθηκεύετε και να ανακτάτε εύκολα δεδομένα από το local storage.

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  // State για την αποθήκευση της τιμής μας
  // Περνάμε την αρχική τιμή στο useState ώστε η λογική να εκτελεστεί μόνο μία φορά
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // Λήψη από το local storage με βάση το κλειδί
      const item = window.localStorage.getItem(key);
      // Ανάλυση του αποθηκευμένου json ή επιστροφή της αρχικής τιμής αν δεν υπάρχει
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // Αν υπάρχει σφάλμα, επιστρέφουμε επίσης την αρχική τιμή
      console.log(error);
      return initialValue;
    }
  });

  // Επιστρέφουμε μια περιτυλιγμένη έκδοση της setter συνάρτησης του useState που...
  // ... αποθηκεύει μόνιμα τη νέα τιμή στο localStorage.
  const setValue = (value) => {
    try {
      // Επιτρέπουμε η τιμή να είναι συνάρτηση ώστε να έχουμε το ίδιο API με το useState
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      // Αποθήκευση στο local storage
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
      // Αποθήκευση του state
      setStoredValue(valueToStore);
    } catch (error) {
      // Μια πιο προχωρημένη υλοποίηση θα χειριζόταν την περίπτωση σφάλματος
      console.log(error);
    }
  };

  useEffect(() => {
    try {
      const item = window.localStorage.getItem(key);
      setStoredValue(item ? JSON.parse(item) : initialValue);
    } catch (error) {
      console.log(error);
    }
  }, [key, initialValue]);

  return [storedValue, setValue];
}

export default useLocalStorage;

Χρήση:

import React from 'react';
import useLocalStorage from './useLocalStorage';

function MyComponent() {
  const [name, setName] = useLocalStorage('name', 'Guest');

  return (
    

Γεια σου, {name}!

setName(e.target.value)} />
); } export default MyComponent;

Παράδειγμα: useFetch

Αυτό το hook ενθυλακώνει τη λογική για την ανάκτηση δεδομένων από ένα API.

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error(`Σφάλμα HTTP! κατάσταση: ${response.status}`);
        }
        const json = await response.json();
        setData(json);
        setLoading(false);
      } catch (error) {
        setError(error);
        setLoading(false);
      }
    }

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

Χρήση:

import React from 'react';
import useFetch from './useFetch';

function MyComponent() {
  const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');

  if (loading) return 

Φόρτωση...

; if (error) return

Σφάλμα: {error.message}

; return (

Τίτλος: {data.title}

Ολοκληρώθηκε: {data.completed ? 'Ναι' : 'Όχι'}

); } export default MyComponent;

Βέλτιστες Πρακτικές για τα Custom Hooks

Για να διασφαλίσετε ότι τα custom hooks σας είναι αποτελεσματικά και συντηρήσιμα, ακολουθήστε αυτές τις βέλτιστες πρακτικές:

Συνηθισμένες Παγίδες προς Αποφυγή

Προχωρημένα Πρότυπα

Σύνθεση Custom Hooks

Τα custom hooks μπορούν να συντεθούν μαζί για να δημιουργήσουν πιο σύνθετη λογική. Για παράδειγμα, θα μπορούσατε να συνδυάσετε ένα useLocalStorage hook με ένα useFetch hook για να αποθηκεύσετε αυτόματα τα ανακτημένα δεδομένα στο local storage.

Διαμοιρασμός Λογικής μεταξύ Hooks

Αν πολλαπλά custom hooks μοιράζονται κοινή λογική, μπορείτε να εξάγετε αυτή τη λογική σε μια ξεχωριστή βοηθητική συνάρτηση (utility function) και να την επαναχρησιμοποιήσετε και στα δύο hooks.

Χρήση του Context με Custom Hooks

Τα custom hooks μπορούν να χρησιμοποιηθούν σε συνδυασμό με το React Context για πρόσβαση και ενημέρωση του καθολικού (global) state. Αυτό σας επιτρέπει να δημιουργήσετε επαναχρησιμοποιήσιμα components που έχουν επίγνωση και μπορούν να αλληλεπιδράσουν με το καθολικό state της εφαρμογής.

Παραδείγματα από τον Πραγματικό Κόσμο

Εδώ είναι μερικά παραδείγματα για το πώς μπορούν να χρησιμοποιηθούν τα custom hooks σε πραγματικές εφαρμογές:

Παράδειγμα : hook useGeolocation για διαπολιτισμικές εφαρμογές όπως χαρτογράφηση ή υπηρεσίες παράδοσης

import { useState, useEffect } from 'react';

function useGeolocation() {
  const [location, setLocation] = useState({
    latitude: null,
    longitude: null,
    error: null,
  });

  useEffect(() => {
    if (!navigator.geolocation) {
      setLocation({
        latitude: null,
        longitude: null,
        error: 'Η Γεωτοποθεσία δεν υποστηρίζεται από αυτόν τον browser.',
      });
      return;
    }

    const watchId = navigator.geolocation.watchPosition(
      (position) => {
        setLocation({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          error: null,
        });
      },
      (error) => {
        setLocation({
          latitude: null,
          longitude: null,
          error: error.message,
        });
      }
    );

    return () => navigator.geolocation.clearWatch(watchId);
  }, []);

  return location;
}

export default useGeolocation;

Συμπέρασμα

Τα custom hooks είναι ένα ισχυρό εργαλείο για τη συγγραφή καθαρότερου, πιο επαναχρησιμοποιήσιμου και πιο συντηρήσιμου κώδικα React. Ενθυλακώνοντας πολύπλοκη λογική σε custom hooks, μπορείτε να απλοποιήσετε τα components σας, να μειώσετε την επανάληψη κώδικα και να βελτιώσετε τη συνολική δομή των εφαρμογών σας. Υιοθετήστε τα custom hooks και απελευθερώστε τις δυνατότητές τους για να χτίσετε πιο στιβαρές και επεκτάσιμες εφαρμογές React.

Ξεκινήστε εντοπίζοντας περιοχές στην υπάρχουσα κωδικοбаза σας όπου η λογική επαναλαμβάνεται σε πολλαπλά components. Στη συνέχεια, αναδομήστε (refactor) αυτή τη λογική σε custom hooks. Με τον καιρό, θα χτίσετε μια βιβλιοθήκη επαναχρησιμοποιήσιμων hooks που θα επιταχύνει τη διαδικασία ανάπτυξής σας και θα βελτιώσει την ποιότητα του κώδικά σας.

Θυμηθείτε να ακολουθείτε τις βέλτιστες πρακτικές, να αποφεύγετε τις συνηθισμένες παγίδες και να εξερευνάτε προχωρημένα πρότυπα για να αξιοποιήσετε στο έπακρο τα custom hooks. Με πρακτική και εμπειρία, θα γίνετε ειδικός στα custom hooks και ένας πιο αποτελεσματικός προγραμματιστής React.